跳到主要内容

[toc]

nginx location

nginx location官方文档

匹配语法

location [ = | ~ | ~* | ^~ ] uri { ... }
location @name { ... }
location [匹配模式] uri {
...
}

location匹配规则

匹配规则总览

匹配模式匹配符优先级
精确匹配=1
前缀匹配^~2
正则匹配~3
正常匹配uri4
全匹配(通用匹配)/5

匹配规则细分

匹配符匹配规则优先级
=精确匹配1
^~以某个字符串开头2
~区分大小写的正则匹配3
~*不区分大小写的正则匹配4
!~区分大小写不匹配的正则5
!~*不区分大小写不匹配的正则6
/通用匹配,任何请求都会匹配到7

location匹配优先级

路径匹配优先级

  • 精确匹配 > 前缀匹配 > 正则匹配 > 正常匹配 > 全匹配

匹配示例

精确匹配

⚠️server_name _ 中的_只是一个无效域名的表示方法

编辑nginx配置文件

server {
listen 80;
server_name _;
# 第1段
location /nginx {
#return 200 "aaa";
root /data/nginx/html4/;
index index.html;
}

# 第2段
location = /nginx {
#return 200 "bbb";
root /data/nginx/html3/;
index index.html;
}
}

创建网站根目录

mkdir -p /data/nginx/html{3,4}/nginx
echo 'html3' >/data/nginx/html3/nginx/index.html
echo 'html4' >/data/nginx/html4/nginx/index.html

访问测试

$ curl 127.0.0.1/nginx
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

$ curl 127.0.0.1/nginx/
html4

精确匹配中 /nginx/ 中优先匹配到第2段,再访问 /nginx/index.html,此次内部跳转uri已经是 /nginx/index.html,而非 = 的,最终访问结果是第1段中的 index.html

信息

结论:精确匹配区分大小写,不能使用正则,访问的URI必须完全与 = 后面的一致,多一个 / 或者少一个 / ,都是不可以的

前缀匹配

编辑nginx配置文件

server {
listen 80;
server_name _;
location ^~ /nginx/ {
rewrite ^ https://www.163.com break;
}

location ^~ /nginx/bcd/ {
rewrite ^ https://www.qq.com break;
}

location ^~ /Abc/ {
rewrite ^ https://www.sina.com.cn break;
}
}

访问测试

访问127.0.0.1/nginx/,在终端中会返回302,在浏览器中会跳转到www.163.com

$ curl 127.0.0.1/nginx/
<html>
<head><title>302 Found</title></head>
<body>
<center><h1>302 Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

访问127.0.0.1/nginx/bcd/,在终端中会返回302,在浏览器中会跳转到www.qq.com

⚠️如果bcd后边不加 / ,跳转页面是www.163.com,即只匹配前缀 /nginx

$ curl 127.0.0.1/nginx/bcd/
<html>
<head><title>302 Found</title></head>
<body>
<center><h1>302 Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

访问一个不存在的页面127.0.0.1/nginx/abcd/,在终端中会返回302,在浏览器中会跳转到www.163.com

$ curl 127.0.0.1/nginx/abcd/
<html>
<head><title>302 Found</title></head>
<body>
<center><h1>302 Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

访问127.0.0.1/Abc/,在终端中会返回302,在浏览器中会跳转到www.sina.com.cn

$ curl 127.0.0.1/nginx/abc/
<html>
<head><title>302 Found</title></head>
<body>
<center><h1>302 Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>
信息

结论:前缀匹配不能使用正则,区分大小写,只要前缀相同,都可以匹配成功,不管后面有没有字符,保证前缀相同即可

正则匹配

编辑nginx配置文件

server {
listen 80;
server_name _;

location ~ /[a-z]nginx/ {
rewrite ^ https://www.baidu.com break;
}

location ~* /[a-z]nginx/ {
rewrite ^ https://www.163.com break;
}
}

访问测试

访问127.0.0.1/anginx/,在终端中会返回302,在浏览器中会跳转到www.baidu.com

$ curl 127.0.0.1/anginx/
<html>
<head><title>302 Found</title></head>
<body>
<center><h1>302 Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

访问127.0.0.1/anginx/abc在终端中会返回302,在浏览器中会跳转到www.baidu.com

$ curl 127.0.0.1/anginx/abc/
<html>
<head><title>302 Found</title></head>
<body>
<center><h1>302 Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

访问127.0.0.1/Anginx/,在终端中会返回302,在浏览器中会跳转到www.163.com

$ curl 127.0.0.1/Anginx/
<html>
<head><title>302 Found</title></head>
<body>
<center><h1>302 Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>
信息

结论:正则匹配 ~ 区分大小写,~* 不区分大小写, 并且与前缀匹配比较类似,只需要匹配模式开头部分,这两种同时存在时,优先匹配区分大小写的

正常匹配

  • 正常匹配就是匹配模式为空的匹配规则

编辑 nginx配置文件

server {
listen 80;
server_name _;

# 第1段
location /nginx/ {
rewrite ^ https://www.baidu.com break;
}

# 第2段
location /[0-9]nginx/ {
rewrite ^ https://www.qq.com break;
}
}

访问测试

访问127.0.0.1/nginx/,在终端中会返回302,在浏览器中会跳转到www.baidu.com

$ curl 127.0.0.1/nginx/
<html>
<head><title>302 Found</title></head>
<body>
<center><h1>302 Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

上述配置文件中第2段访问不生效,404

⚠️location ^~ /nginx/location /nginx/不能同时出现

信息

结论:正常匹配与前缀匹配的差别,只在于优先级

全匹配(通用匹配)

编辑nginx配置文件

server {
listen 80;
server_name _;

location / {
root /data/nginx/html;
index index.html index.htm;
}
}

全匹配没有匹配模式,并且匹配的uri仅是一个斜杠/,通常用在一个默认页面的地方

命名匹配

命名匹配一般用于静态页面或者错误页面(404,500等),并且这个命名匹配中,不允许有alias。

error_page 404 = @notfound;
location @notfound {
rewrite ^ https://www.baidu.com break;
}

优先级验证综合实验

编辑nginx配置文件

⚠️前缀匹配和正常匹配不能同时存在

server {
listen 80;
server_name _;

# 全匹配,这里/data/nginx/html/下面有一个nginx文件夹,里面有index.html,内容是nginx location test
location / {
root /data/nginx/html;
index index.html;
}

# 正常匹配
location /nginx/ {
rewrite ^/nginx/$ https://www.sina.com.cn/ break;
}

# 正则匹配
location ~ /[a-z]ginx/ {
rewrite ^/nginx/$ https://www.163.com/ break;
}

# 前缀匹配
location ^~ /nginx/ {
rewrite ^/nginx/$ https://www.baidu.com/ break;
}

# 精确匹配
location = /nginx/ {
rewrite ^/nginx/$ https://www.qq.com/ break;
}

}

创建网站根目录

mkdir -p /data/nginx/html/nginx
echo 'nginx location test' > /data/nginx/html/nginx/index.html

第一步、把正常匹配注释掉,留下前缀匹配,然后浏览器访问IP/nginx/,第一次返回的结果是跳转到了www.qq.com,证明了=精确匹配优先级是最大的

第二步、把精确匹配注释掉,然后浏览器访问IP/nginx/,结果是跳转到了www.baidu.com,证明了^~前缀匹配优先级是仅次于精确匹配

第三步、因为前缀匹配和正常匹配不能同时存在,所以这一步比较第一步和第二步,还是把精确匹配注释掉,这次把前缀匹配注释掉,把正常匹配注释打开,结果是跳转到了www.163.com,说明正则匹配的优先级是大于正常匹配的,同时也验证了前缀匹配优先级第2,正则匹配优先级第3,正常匹配优先级第4

第四步、现在只剩下全匹配了,所以全匹配的优先级最低

信息

结论:各匹配优先级如下 精确匹配 > 前缀匹配 > 正则匹配 > 正常匹配 > 全匹配

匹配原则除了这个优先级外,还有一个就是在相同指令模式匹配中,匹配度最大的URI优先

root与alias

nginx配置 location规则中的 uri 往往都是匹配一个目录。

root

编辑nginx配置文件

server {
listen 80;
server_name _;

location /nginx/ {
root /data/nginx/html/;
index index.html index.htm;
}
}

使用root关键字指定网站根目录

当访问127.0.0.1/nginx/index.html时,如果/data/nginx/html/这个目录下没有nginx/index.html或者没有nginx目录,则会报错404

原因是使用root指定目录时,目录下边要包括location后面的uri,否则就会报错

使用root指定目录时,不会将location uri配置的路径去掉,即访问的路径是/data/nginx/html/nginx

访问测试

#不创建目录nginx
mkdir -p /data/nginx/html/
echo 'abc' >/data/nginx.html/index.html

#访问报错404
$ curl 127.0.0.1/nginx/
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

alias

编辑nginx配置文件

server {
listen 80;
server_name _;

location /nginx/ {
alias /data/nginx/html/;
index index.html index.htm;
}
}

使用alias关键字指定网站根目录

当访问127.0.0.1/nginx/index.html时,只要保证alias指定的目录中有index.html即可,即使没有目录nginx,它会将location uri配置的路径去掉,实际访问的就是/data/nginx/html/index.html

访问测试

#不创建目录nginx
mkdir -p /data/nginx/html/
echo 'abc' >/data/nginx.html/index.html


$ curl 127.0.0.1/nginx/
abc
信息

结论:root 指定的目录中,需要location中的 uri 路径目录确实存在,alias 指定的目录中不需要 location中的uri 路径目录存在

代理服务器 proxy_pass 中有无 /

实验环境

角色主机名IP
真实webweb0110.0.0.10
nginx代理nginx-proxy10.0.0.51

后端真实web服务配置

后端真实web服务nginx 10.0.0.10配置

server {
listen 80;
server_name _;

location /nginx/ {
root /data/nginx/html/;
index index.html index.htm;
}

location /ng/ {
root /data/nginx/html/;
index index.html index.htm;
}

location /k8s/ {
root /data/nginx/html/;
index index.html index.htm;
}
}

创建网站根目录

mkdir -p /data/nginx/html/{nginx,ng,k8s}
echo 'nginx' >/data/nginx/html/nginx/index.html
echo 'ng' >/data/nginx/html/ng/index.html
echo 'k8s' >/data/nginx/html/k8s/index.html

访问测试

$ curl 127.0.0.1/nginx/
nginx

$ curl 127.0.0.1/ng/
ng

$ curl 127.0.0.1/k8s/
k8s

proxy_pass无目录无/

代理服务器nginx 10.0.0.51配置中 proxy_pass 无'/'验证

server {
listen 80;
server_name _;

location /nginx {
#没有/指的是proxy_pass后边的url没有/后缀
proxy_pass http://10.0.0.10;
}
}

访问测试

$ curl 10.0.0.51/nginx/
nginx

$ curl -L 10.0.0.51/nginx
nginx

真实web服务10.0.0.10nginx访问日志如下

10.0.0.51 - - [18/Jun/2020:17:46:53 +0800] "GET /nginx/ HTTP/1.0" 200 6 "-" "curl/7.29.0" "-"
信息

结论:如果 proxy_pass 反向代理中,在server后面没有 / 反斜杠的话,访问的是 http://10.0.0.10/nginx/index.html,它会去上游真实服务器去匹配代理服务器上面location URI

proxy_pass无目录有/

代理服务器nginx 10.0.0.51配置中 proxy_pass '/'验证

server {
listen 80;
server_name _;

location /nginx {
#有/指的是proxy_pass后边的url有/后缀
proxy_pass http://10.0.0.10/;
}
}

访问测试

因为访问的是真实服务器的/,但是并没有在真实服务器根中写入访问页面

$ curl 10.0.0.51/nginx/
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

真实web服务10.0.0.10nginx访问日志如下

10.0.0.51 - - [18/Jun/2020:17:51:32 +0800] "GET / HTTP/1.0" 404 153 "-" "curl/7.29.0" "-"
信息

结论:如果 proxy_pass 反向代理中,在server后面有 / 反斜杠的话,访问的是 http://10.0.0.10/index.html,它会忽略掉代理服务器上面location中的URI,直接访问代理服务器上面的 /

proxy_pass有目录无/

代理服务器10.0.0.51proxy_pass后面增加目录,但不加 /

server {
listen 80;
server_name _;

location /nginx/ {
proxy_pass http://10.0.0.10/nginx;
}
}

访问测试

因为访问的是真实服务器的/,但是并没有在真实服务器根中写入访问页面

$ curl 10.0.0.51/nginx/
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.18.0</center>
</body>
</html>

真实web服务10.0.0.10nginx访问日志如下

10.0.0.51 - - [18/Jun/2020:18:04:40 +0800] "GET /nginx HTTP/1.0" 404 153 "-" "curl/7.29.0" "-"
信息

结论:如果 proxy_pass 反向代理中,在server后面有URI, 但没有 / 反斜杠的话,访问的是 http://10.0.0.10/nginx,它会去上游真实服务器去匹配代理服务器上面的URI

proxy_pass有目录有/

代理服务器10.0.0.51proxy_pass后面增加目录并且加 /

server {
listen 80;
server_name _;

location /nginx/ {
proxy_pass http://10.0.0.10/nginx/;
}
}

访问测试

$ curl 10.0.0.51/nginx/
nginx

真实web服务10.0.0.10nginx访问日志如下

10.0.0.51 - - [18/Jun/2020:17:58:47 +0800] "GET /nginx/ HTTP/1.0" 200 6 "-" "curl/7.29.0" "-"
信息

结论:如果 proxy_pass 反向代理中有目录,并且有 / 反斜杠的话,访问的是http://10.0.0.10/nginx/index.html,它会忽略掉代理服务器上面location中的URI,直接访问代理服务器上面的目录+ / 的形式

测试结果最终对比

iShot_2024-05-10_13.03.44